using System;
using System.Collections.Generic;
using System.Text;
using Jasongozy.Alaton;
using System.Text.RegularExpressions;
using Jasongozy.Copor.Utility;
namespace Jasongozy.Copor {
    public class LoopFuncation : AbstractFunction {
        bool isForeachLoop;
        bool onlyOneLine;


        public override string FuncName {
            get { return "Loop"; }
        }
        public override void IniteProperty(Dictionary<string, string> input) {
            base.IniteProperty(input);
            isForeachLoop = !Property.ContainsKey("index");
            onlyOneLine = Property.ContainsKey("only-one-line") && TypeParser.ToBool(Property["only-one-line"], false);
        }
        public override string Execute() {
            InnerReplace();
            string source = Property["source"];
            string tempsource = source;
            int length = 0;

            if (source.Split(',').Length > 1) {
                tempsource = source.Split(',')[1];
                string collectionKey = GetParamName(tempsource);
                if (string.IsNullOrEmpty(collectionKey)) {
                    Console.WriteLine(FuncName + " collectionKey:" + collectionKey);
                    return "";
                }
                string name = TemplateParamInjection.ReplaceFuncPro(source.Split(',')[0], Property);
                name = TemplateParamInjection.Injection(name);
                if (!string.IsNullOrEmpty(name)) {
                    length = TemplateParameter.Instance.SpecialAryParams[name][collectionKey].Count;
                }

            } else {
                string collectionKey = GetParamName(tempsource);
                if (string.IsNullOrEmpty(collectionKey)) {
                    Console.WriteLine(FuncName + " collectionKey:" + collectionKey);
                    return "";
                }
                length = TemplateParameter.Instance.ComplexParams[collectionKey].Length;
            }

            StringBuilder sb = new StringBuilder();
            string content = Property["content"];
            string split = Property.ContainsKey("split") ? Property["split"] : "";

            if (isForeachLoop) {
                string tempVar = Property["param"];
                for (int i = 0; i < length; i++) {
                    string newString = tempsource.Insert(tempsource.LastIndexOf("}"), "[" + i + "]");
                    string newContent = content.Replace(tempVar, newString);
                    sb.Append(newContent);
                    if (onlyOneLine) {
                        sb.Append(split);
                    } else {
                        sb.AppendLine(split);
                    }

                }
            } else {
                string indexVar = Property["index"];
                int startIndex = Property.ContainsKey("start") ? TypeParser.ToInt(Property["start"], 0) : 0;
                for (int i = startIndex; i < length; i++) {
                    string newContent = content.Replace(indexVar, i.ToString());
                    sb.Append(newContent);
                    if (onlyOneLine) {
                        sb.Append(split);
                    } else {
                        sb.AppendLine(split);
                    }
                }
            }

            if (sb.ToString().EndsWith(split) && split.Length > 0) {
                sb.Remove(sb.Length - split.Length, split.Length);
            }

            return sb.ToString();
        }


    }

    public class LoadProcFuncation : AbstractFunction {
        public override string FuncName {
            get { return "LoadProc"; }
        }

        public override string Execute() {
            string args = Property["args"];
            if (RegexMatch.TEMPLATE_PARAM_MATCH.IsMatch(args)) {
                args = RegexMatch.TEMPLATE_PARAM_MATCH.Replace(args, delegate(Match tm) {
                    string key = GetParamName(tm.Value);
                    if (TemplateParameter.Instance.SampleParams.ContainsKey(key)) {
                        return TemplateParameter.Instance.SampleParams[key];
                    }
                    return "";
                });
            }
            MySqlProcSchema schema = MySqlDBHelper.GetSqlProcInfo(TemplateParameter.Instance.SampleParams["ConnectionStr"],
                                                                                                              TemplateParameter.Instance.SampleParams["DbName"], args);
            TemplateParameter.Instance.AddMySqlProcParams(schema);
            return "";

        }
    }

    public class IsValueTypeFunction : AbstractFunction {
        public override string FuncName {
            get { return "IsValueType"; }
        }
        public override void IniteProperty(Dictionary<string, string> input) {
            base.IniteProperty(input);
            CheckInput();
        }
        public override string Execute() {
            string columnTypeKey = GetParamName(Property["source"]);
            string args = Property["args"];
            StringBuilder code = new StringBuilder();

            int index = TypeParser.ToInt(args.Split(',')[0], -1);
            //if (index = -1) {
            //    index = Array.IndexOf(TemplateParameter.Instance.ComplexParams["Columns"], args.Split(',')[0]);
            //}
            string typeName = TemplateParameter.Instance.ComplexParams[columnTypeKey][index];
            //code.Append(Property["source"].Insert(Property["source"].LastIndexOf("}"), "[" + index + "]"));
            if (Type.GetType(typeName).IsValueType) {
                return "True";
            }
            return "False";
        }

        protected override void CheckInput() {
            string args = Property["args"];
            if (string.IsNullOrEmpty(args))
                throw new ArgumentException("Functaion :" + FuncName + " must input argument!");
            string[] argsAry = args.Split(',');
            if (argsAry.Length > 1 || (argsAry[0].IndexOf("$") < 0 && TypeParser.ToInt(argsAry[0], -1) < 0)) {
                throw new ArgumentException("The Argument of Functaion :" + FuncName + " is Invalid");
            }
        }
    }

    public class GetValueForProcParamFunction : AbstractFunction {
        public override string FuncName {
            get { return "GetValueForProcParam"; }
        }

        public override string Execute() {
            string[] args = Property["args"].Split(',');
            string paramName = TemplateParamInjection.Injection(args[0]);
            string prefix = args.Length > 1 ? args[1] : "";
            string arguPrefix = args.Length > 2 ? args[2] : "";
            string columnName = paramName.Replace(prefix, "");
            if (columnName.EndsWith("s")) {
                columnName = columnName.Substring(0, columnName.Length - 1);
            }

            StringBuilder code = new StringBuilder();
            if (columnName == paramName) { 
                code.Append("null"); 
            } else {
                string columnTypeKey = GetParamName(Property["source"]);
                int index = Array.IndexOf(TemplateParameter.Instance.ComplexParams["Columns"], columnName);
                string typeName = TemplateParameter.Instance.ComplexParams[columnTypeKey][index];
                if (Type.GetType(typeName).IsValueType) {
                    string name = arguPrefix + "{$Columns[" + index + "]}";
                    code.AppendFormat("{0}.HasValue?(Object){0}.Value:null", name);
                } else {
                    code.Append(arguPrefix);
                    code.Append("{$Columns[" + index + "]}");
                }
            }
            return code.ToString();
        }
    }

    public class IfJudgeFuncation : AbstractFunction {
        public override string FuncName {
            get { return "If"; }
        }

        public override string Execute() {
            //string test = Property["test"];
            bool test = TypeParser.ToBool(Property["test"], false);
            bool arg = TypeParser.ToBool(Property["args"], false);
            string content = Property["content"];
            if (test == arg) {
                return content;
            }
            return "";
        }
    }
}
